﻿Friend Class ArphoonChecker
    Implements IDisposable

    Public Sub New(ByVal xfilename As String)
        Filename = xfilename
        Errors = 0
    End Sub

    Public Property Filename As String
    Public Property Errors As Long

    Private _arpsEngine As Arps.Engine

    Public Sub Check()
        AddLogV("Initializing Arphoon Packaging Library...")
        _arpsEngine = New Arps.Engine()
        AddLogV(" using: " & Arps.Engine.EngineIdentifier & " (" & Arps.Engine.EngineDeveloper & ")")

        AddLog()
        AddLog("Mounting target package...")

        ' Check if Package requires a Password
        Try
            ' Get Package protocol
            Dim protocol As String
            protocol = _arpsEngine.GetPackageProtocol(Filename)
            AddLog("Package compiled using protocol " & protocol)

            If _arpsEngine.HaveEncryptionSupport(protocol) Then
                If (CurrentConfiguration.PackagePassword Is Nothing) OrElse (CurrentConfiguration.PackagePassword.Length < 1) Then
                    AddLog("Encrypted Package is Password Protected.")
                    AddLog()
                    AddLog("Input package password for decryption:")
                    Dim key As String = Console.ReadLine()
                    ClearLog(True)
                    ClearLog(True)
                    ClearLog(True)
                    AddLog("Password successfully readed from console.")
                    Configuration.CurrentConfiguration.PackagePassword = key
                Else
                    AddLog("Encrypted Package is Password Protected. Using specified key for mounting...")
                End If
            End If
        Catch ex As Exception
            AddLog("Fatal!: Unhandled exception raised while identifying package protocol.")
            AddLog("    ex: " & ex.Message)
            _arpsEngine.Dispose()
            _arpsEngine = Nothing
            Exit Sub
        End Try

        Dim packageMountCode As Arps.Engine.PackageMountReturnCode
        packageMountCode = _arpsEngine.Mount(Filename, Configuration.CurrentConfiguration.PackagePassword)

        If packageMountCode = Arps.Engine.PackageMountReturnCode.MountSuccess Then
            AddLogV("Package mount success!")
            AddLogV(" Protocol: " & _arpsEngine.MountedPackage.Package.ProtocolVersion)
            AddLogV(" Compiler: " & _arpsEngine.MountedPackage.Package.CompilerDetails.ProductName)
            AddLogV("           By " & _arpsEngine.MountedPackage.Package.CompilerDetails.ProductOwner)
            AddLogV("           V. " & _arpsEngine.MountedPackage.Package.CompilerDetails.ProductVersion.ToString())
            AddLogV("           Identified as " & _arpsEngine.MountedPackage.Package.CompilerDetails.ProductIdentifier)
            AddLogV("           Targetting Architecture " & _arpsEngine.MountedPackage.Package.CompilerDetails.ProductArchitecture.ToString)
            AddLogV("           Comments: " & _arpsEngine.MountedPackage.Package.CompilerDetails.Comments)
            AddLog(" Compiled at: " & _arpsEngine.MountedPackage.Package.CompilerDetails.CompileTime.ToString(System.Globalization.CultureInfo.CurrentCulture))
        Else
            AddLog("ERROR: Package mount failed with error code:")
            AddLog("       " & packageMountCode.ToString())
            _arpsEngine.Dispose()
            _arpsEngine = Nothing
            Exit Sub
        End If

        Dim startTime As Date = Now

        Dim returned As Boolean = True
        Dim totalerrors As ULong = 0
        Dim testIndex As Integer = 1

        ' VirtualTreeCheck test
        AddLog("[" & testIndex & "] Checking Virtual Tree Structure...")
        returned = ArphoonTest.Integrity.VirtualTreeCheck(_arpsEngine, totalerrors)
        AddLogV("VirtualTreeCheck test result: " & returned.ToString() & "; errors: " & totalerrors)
        Errors += totalerrors
        totalerrors = 0
        If returned = False Then
            _arpsEngine.Dispose()
            AddLog("Package test FAILED.")
            AddLog(Errors & " errors found.")
            End
        End If

        ' DataValidationCheck test
        testIndex += 1
        AddLog("[" & testIndex & "] Checking payload...")
        returned = ArphoonTest.Validation.DataValidationTest(_arpsEngine, totalerrors)
        AddLogV("DataValidationCheck test result: " & returned.ToString() & "; errors: " & totalerrors)
        Errors += totalerrors
        totalerrors = 0
        If returned = False Then
            _arpsEngine.Dispose()
            AddLog("Package test FAILED.")
            AddLog(Errors & " errors found.")
            End
        End If

        AddLog()
        AddLog("Package Check Complete.")
        AddLog("Entire process took: " & GetFormattedTime(Now - startTime))
        AddLog(Errors & " errors found.")
    End Sub

    Public Function GetFormattedTime(ByVal _timespan As TimeSpan) As String
        Dim daysSuffix As String = " Days."
        Dim hoursSuffix As String = " h."
        Dim minutesSuffix As String = " m."
        Dim secondsSuffix As String = " s."
        Dim millisecondsSuffix As String = " ms."

        Dim output As String = ""

        If Not _timespan.Days = 0 Then output = _timespan.Days & daysSuffix & " "
        If Not _timespan.Hours = 0 Then output &= _timespan.Hours & hoursSuffix & " "
        If Not _timespan.Minutes = 0 Then output &= _timespan.Minutes & minutesSuffix & " "
        If Not _timespan.Seconds = 0 Then output &= _timespan.Seconds & secondsSuffix & " "
        If Not _timespan.Milliseconds = 0 Then output &= _timespan.Milliseconds & millisecondsSuffix

        output = Trim(output)

        If output = "" Then output = "0" & millisecondsSuffix

        Return output
    End Function

#Region "IDisposable Support"
    Private disposedValue As Boolean ' Para detectar llamadas redundantes

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: eliminar estado administrado (objetos administrados).
                If (_arpsEngine IsNot Nothing) Then _arpsEngine.Dispose()
                _arpsEngine = Nothing
            End If

            ' TODO: liberar recursos no administrados (objetos no administrados) e invalidar Finalize() below.
            ' TODO: Establecer campos grandes como Null.
        End If
        Me.disposedValue = True
    End Sub

    ' TODO: invalidar Finalize() sólo si la instrucción Dispose(ByVal disposing As Boolean) anterior tiene código para liberar recursos no administrados.
    'Protected Overrides Sub Finalize()
    '    ' No cambie este código. Ponga el código de limpieza en la instrucción Dispose(ByVal disposing As Boolean) anterior.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' Visual Basic agregó este código para implementar correctamente el modelo descartable.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' No cambie este código. Coloque el código de limpieza en Dispose (ByVal que se dispone como Boolean).
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class